﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Android.App;
using Android.Content;
using Android.Content.Res;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.Support.Design.Widget;
using Android.Support.V4.App;
using Android.Support.V4.Content;
using Android.Support.V4.Graphics.Drawable;
using Android.Support.V4.View;
using Android.Util;
using Android.Views;
using Android.Views.InputMethods;
using Android.Widget;
using Com.Gcssloop.Widget;
using FFImageLoading;
using FFImageLoading.Helpers;
using hotfix;
using mb;
using mb.Droid;
using Shared;
using Xamarin.Forms.Platform.Android;
using Fragment = Android.Support.V4.App.Fragment;
using Orientation = Android.Widget.Orientation;

namespace libmp
{
    public class GlobalImpl : hotfix.IGlobal
    {
        ILog logger = ServiceLocator.Instance.Get<ILog>();
        public static SimpleVideoServer VideoServer { get; set; }
        public void OnDidLaunch()
        {
            logger.Log("android version", (int) Android.OS.Build.VERSION.SdkInt);
            ConfigFFImage();
            StartVideoServer();

            MainView.Load();
        }

        void StartVideoServer()
        {
            VideoServer = new SimpleVideoServer();
            logger.Log("video server start at", VideoServer.Port);
            // var res = Http.MakeRequest(new Http.Option
            // {
            //     Url = $"http://localhost:{VideoServer.Port}/check",
            //         Method = HttpMethod.Get,
            //         OnFinish = (ok, code, msg) =>
            //         {
            //             logger.Log("check video server <<<<<", ok, code, msg);
            //         }
            // });

        }

        void ConfigFFImage()
        {
            var cfg = FFImageLoading.Config.Configuration.Default;
            cfg.Logger = new CustomMiniLogger();
            ImageService.Instance.Initialize(cfg);

        }

    }

    class CustomMiniLogger : IMiniLogger
    {
        public void Debug(string message) { }

        public void Error(string errorMessage)
        {
            App.logger.Log("ffimage error1", errorMessage);
        }

        public void Error(string errorMessage, Exception ex)
        {
            App.logger.Log("ffimage error2", errorMessage, ex.Message);
        }
    }

    public static partial class Util
    {
        static ILog logger = App.logger;
        static float density = Resources.System.DisplayMetrics.Density;
        public static Android.Graphics.Color MainColor = Android.Graphics.Color.Rgb(251, 114, 153);
        public static Android.Graphics.Color MainBKColor = Android.Graphics.Color.Rgb(244, 244, 244);
        public static int dpToPx(int dp)
        {
            return (int) (dp * density + 0.5f);
        }

        public static int pxToDp(int px)
        {
            return (int) (px / density);
        }

        public static MyFragment FragmentFrom(Type ownerClass)
        {
            var mi = ownerClass.GetMethod("CreateFragment");
            return mi.Invoke(null, null) as MyFragment;
        }

        public static StateListDrawable MakeDrawableSelector(Drawable normal, Drawable pressed = null, Drawable selected = null)
        {
            StateListDrawable res = new StateListDrawable();
            if (pressed != null)
                res.AddState(new int[] { Android.Resource.Attribute.StateEnabled, Android.Resource.Attribute.StatePressed }, pressed);
            if (selected != null)
                res.AddState(new int[] { Android.Resource.Attribute.StateSelected }, selected);
            res.AddState(new int[] { }, normal);
            return res;
        }

        public static Drawable MakeDrawable(string path)
        {
            var ctx = StartActivity.This;
            var fullpath = path[0] == '/' ? path : App.HotStorageRoot + $"/res/{path}";
            // var drawer = Drawable.CreateFromPath(fullpath);
            Bitmap b = BitmapFactory.DecodeFile(fullpath);
            Drawable d2 = new BitmapDrawable(ctx.Resources, b);
            // App.logger.Log("bitmap", b.Width, b.Height, path);
            return d2;
        }

        public static Drawable WithColor(this Drawable dr, Color c)
        {
            dr.SetColorFilter(c, PorterDuff.Mode.SrcIn);
            return dr;
        }

        public static Color ClearColor = new Color(0);
        public static ColorStateList MakeColorStateList(Color normal) => MakeColorStateList(normal, ClearColor, ClearColor);
        public static ColorStateList MakeColorStateList(Color normal, Color selected) => MakeColorStateList(normal, selected, ClearColor);
        public static ColorStateList MakeColorStateList(Color normal, Color selected, Color focused)
        {

            var states = new List<int[]>();
            var colors = new List<int>();

            if (selected != ClearColor)
            {
                states.Add(new int[] { Android.Resource.Attribute.StateSelected });
                colors.Add(selected);
            };

            if (focused != ClearColor)
            {
                states.Add(new int[] { Android.Resource.Attribute.StateFocused });
                colors.Add(focused);
            };

            states.Add(new int[] { Android.Resource.Attribute.StateEnabled });
            colors.Add(normal);
            return new ColorStateList(states.ToArray(), colors.ToArray());
        }
        public static ColorStateList MakeColorStateList((Color color, int state) [] list)
        {
            var states = new List<int[]>();
            var colors = new List<int>();

            foreach (var item in list)
            {
                states.Add(new int[] { item.state });
                colors.Add(item.color);

            }
            return new ColorStateList(states.ToArray(), colors.ToArray());
        }

        public static RoundedBitmapDrawable MakeRoundedDrawableFromFile(string path)
        {
            var ctx = StartActivity.This;
            var fullpath = App.HotStorageRoot + $"/res/{path}";
            var bmp = BitmapFactory.DecodeFile(fullpath);
            var rd = RoundedBitmapDrawableFactory.Create(ctx.Resources, bmp);
            rd.Circular = true;
            return rd;
        }

        public static ImageView MakeImageView(string path, bool round = false)
        {
            var ctx = StartActivity.This;
            var v = new ImageView(ctx);
            v.SetImageDrawable(round?MakeRoundedDrawableFromFile(path) : DrawableFromFile(path));
            // v.SetBackgroundColor(Color.Black);
            return v;
        }
        public static Drawable DrawableFromFile(string path)
        {
            var ctx = StartActivity.This;
            var fullpath = path[0] == '/' ? path : App.HotStorageRoot + $"/res/{path}";
            // var drawer = Drawable.CreateFromPath(fullpath);
            Bitmap b = BitmapFactory.DecodeFile(fullpath);
            Drawable d2 = new BitmapDrawable(ctx.Resources, b);
            // logger.Log("bitmap", b.Width, b.Height);
            return d2;
        }

        public static GradientDrawable MakeRoundedRect(Color color, float radius)
        {
            var radii = new float[8];
            radii.Fill(radius);
            return MakeRoundedRect(color, radii, 0, Color.Black);
        }
        public static GradientDrawable MakeRoundedRect(Color color, float[] radius, int strokeWidth, Color strokeColor)
        {
            if (radius.Length == 4)
            {
                var newRadius = new float[8];
                for (int i = 0; i < 4; i++)
                {
                    newRadius[i * 2] = newRadius[i * 2 + 1] = radius[i];
                }
                radius = newRadius;
            }

            GradientDrawable gd = new GradientDrawable();
            gd.SetColor(color);
            gd.SetCornerRadii(radius);
            if (strokeWidth > 0)
                gd.SetStroke(strokeWidth, strokeColor);
            return gd;
        }

        public static ViewGroup MakeFlatTextButton(string title, int width = -1)
        {
            return MakeFlatTextButton(title, width, new Color[] { Util.MainColor, Util.MainBKColor });

        }
        public static ViewGroup MakeFlatTextButton(string title, int width, Color[] colors)
        {
            var ctx = StartActivity.This;
            var rootLayout =
                new LinearLayout(ctx)
                {
                    Orientation = Orientation.Horizontal, Clickable = true,
                        Background = Util.MakeDrawableSelector(
                            Util.MakeRoundedRect(colors[0], 20),
                            Util.MakeRoundedRect(colors[0].Darker(0.9f), 20)),
                        LayoutParameters = new ViewGroup.LayoutParams(width, Util.dpToPx(40))
                }
                .AddViewEx(
                    new TextView(ctx)
                    {
                        Text = title, Gravity = GravityFlags.Center,
                    }
                    .SetTextColorEx(colors[1])
                    .SetTextSizeEx(ComplexUnitType.Pt, 9)
                    .SetTypefaceEx(Typeface.Default, TypefaceStyle.Bold),
                    new LinearLayout.LayoutParams(-1, -2)
                );

            rootLayout.SetVerticalGravity(GravityFlags.CenterVertical);
            return rootLayout;
        }

        public static ViewGroup MakeFlatIconTextButton(string img, string title, int width = -1)
        {
            var ctx = StartActivity.This;
            var rootLayout = new LinearLayout(ctx);
            rootLayout.Orientation = Orientation.Horizontal;
            rootLayout.LayoutParameters = new LinearLayout.LayoutParams(width, Util.dpToPx(50)) { TopMargin = 1, };
            rootLayout.Clickable = true;
            rootLayout.Background = Util.MakeDrawableSelector(new ColorDrawable(Color.White), new ColorDrawable(new Color((int) (Color.White * 0.9))));
            rootLayout.SetVerticalGravity(GravityFlags.CenterVertical);

            //image
            var imgs = 50;
            rootLayout.AddView(Util.MakeImageView(img), new LinearLayout.LayoutParams(imgs, imgs) { LeftMargin = Util.dpToPx(10), RightMargin = Util.dpToPx(10) });

            //text
            rootLayout.AddView(new TextView(ctx) { Text = title });

            return rootLayout;
        }

        public static void HideKeyboard(View fv)
        {
            var ctx = StartActivity.This;
            fv.ClearFocus();
            ((InputMethodManager) ctx.GetSystemService(Context.InputMethodService)).HideSoftInputFromWindow(fv.WindowToken, 0);
        }

        public static void InspectFragment()
        {
            var ctx = StartActivity.This;
            var fm = ctx.SupportFragmentManager;
            for (int entry = 0; entry < fm.BackStackEntryCount; entry++)
            {
                logger.Log("Found fragment: ", fm.GetBackStackEntryAt(entry).Name);
            }
        }
    }

    public static partial class MyExtension
    {
        public static Color Darker(this Color c, float per)
        {
            return new Color((byte) (c.R * per), (byte) (c.G * per), (byte) (c.B * per), c.A);
        }

        public static T FillParent<T>(this T view) where T : View
        {
            view.LayoutParameters = new LinearLayout.LayoutParams(-1, -1);
            return view;
        }
        public static T SetLayoutParam<T>(this T view, ViewGroup.LayoutParams lp) where T : View
        {
            view.LayoutParameters = lp;
            return view;
        }

        public static T SetMarginEx<T>(this T view, int left = -1, int top = -1, int right = -1, int bottom = -1) where T : View
        {
            if (view.LayoutParameters == null)
                view.LayoutParameters = new LinearLayout.LayoutParams(-2, -2);

            var lp = view.LayoutParameters as LinearLayout.LayoutParams;
            if (left != -1) lp.LeftMargin = left;
            if (top != -1) lp.TopMargin = top;
            if (right != -1) lp.RightMargin = right;
            if (bottom != -1) lp.BottomMargin = bottom;

            return view;
        }

        public static T SetParent<T>(this T view, ViewGroup parent) where T : View
        {
            parent.AddView(view);
            return view;
        }
        public static T SetClickHandler<T>(this T view, EventHandler handler) where T : View
        {
            view.Clickable = true;
            view.Click += handler;
            return view;
        }
        public static T AddViewEx<T>(this T view, View child, ViewGroup.LayoutParams lp = null) where T : ViewGroup
        {
            if (lp == null)
                view.AddView(child);
            else
                view.AddView(child, lp);
            return view;
        }

        public static LinearLayout SetGravityEx(this LinearLayout view, GravityFlags gf)
        {
            view.SetGravity(gf);
            return view;
        }

        public static ImageView SetImage(this ImageView view, string path)
        {
            return view.SetImageDrawableEx(Util.DrawableFromFile(path));
        }
        public static ImageView SetImageDrawableEx(this ImageView view, Drawable drawable)
        {
            view.SetImageDrawable(drawable);
            return view;
        }

        public static TextView SetTextColorEx(this TextView view, Color c)
        {
            view.SetTextColor(c);
            return view;
        }

        public static TextView SetTypefaceEx(this TextView view, Typeface tf, TypefaceStyle style)
        {
            view.SetTypeface(tf, style);
            return view;
        }
        public static TextView SetTextSizeEx(this TextView view, Android.Util.ComplexUnitType unit, float size)
        {
            view.SetTextSize(unit, size);
            return view;
        }

        public static void SetCursorColor(this EditText view, Color color)
        {
            try
            {
                var jclass = Java.Lang.Class.FromType(typeof(TextView));
                var fRes = jclass.GetDeclaredField("mCursorDrawableRes");
                fRes.Accessible = true;
                int drawableResId = fRes.GetInt(view);

                // Get the editor
                var fEditor = jclass.GetDeclaredField("mEditor");
                fEditor.Accessible = true;
                var editor = fEditor.Get(view);

                if ((int) Android.OS.Build.VERSION.SdkInt >= 28)
                {
                    // Get the drawable and set a color filter
                    Drawable drawable = ContextCompat.GetDrawable(view.Context, drawableResId);
                    drawable.SetColorFilter(color, PorterDuff.Mode.SrcIn);

                    // Set the drawables
                    try
                    {
                        var fDrawable = editor.Class.GetDeclaredField("mDrawableForCursor");
                        fDrawable.Accessible = true;
                        fDrawable.Set(editor, drawable);
                    }
                    catch (Exception e) { }

                }
                else
                {
                    // Get the drawable and set a color filter
                    Drawable drawable = ContextCompat.GetDrawable(view.Context, drawableResId);
                    drawable.SetColorFilter(color, PorterDuff.Mode.SrcIn);
                    Drawable[] drawables = { drawable, drawable };

                    // Set the drawables
                    var fDrawable = editor.Class.GetDeclaredField("mCursorDrawable");
                    fDrawable.Accessible = true;
                    fDrawable.Set(editor, drawables);
                }

            }
            catch (System.Exception e)
            {
                App.logger.Log("setcursorcolor fail", e.ToString());
            }
        }

        public static void SetParent(this BasePage page, Fragment frag, View view)
        {
            frag.ChildFragmentManager
                .BeginTransaction()
                .Replace(view.Id, page.CreateSupportFragment(frag.Activity))
                .Commit();

        }

    }
}